package com.base.components.common.util;

import com.google.common.collect.ImmutableMap;
import com.google.common.collect.Maps;
import org.apache.commons.lang3.StringUtils;

import javax.persistence.Column;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

/**
 * ColumnsUtil 数据库字段生成工具
 *
 * @author <a href="drakelee1221@gmail.com">LiGeng</a>
 * @version v1.0.0
 * @date 2019-01-18 13:57
 */
public abstract class ColumnsUtil {
  private static final Map<Class, Map<String, String>> CLASS_MAP = new ConcurrentHashMap<>();

  /**
   * 将实体类字段的 javax.persistence.Column 注解，生成数据库查询字段
   * @param domainClass -实体类名
   * @param alias - 表别名，如： t
   * @return String 格式： ${Column注解name} ${实体类字段}, ${Column注解name} ${实体类字段}, ....
   */
  public static String findColumns(Class domainClass, String alias) {
    Map<String, String> map = findColumns(domainClass);
    if(map != null && !map.isEmpty()){
      alias = StringUtils.isBlank(alias) ? "" : addPoint(alias);
      StringBuilder sb = new StringBuilder(" ");
      boolean first = true;
      for (Map.Entry<?, ?> entry : map.entrySet()) {
        if (!first) {
          sb.append(", ");
        }
        first = false;
        sb.append(alias).append(entry.getValue()).append(" ").append(entry.getKey());
      }
      return sb.append(" ").toString();
    }
    return "";
  }

  /**
   * 将实体类字段的 javax.persistence.Column 注解，生成对应 Map
   * @param domainClass -实体类名
   * @return Map [${实体类字段}=${Column注解name}]
   */
  public static Map<String, String> findColumns(Class domainClass) {
    Map<String, String> domain = CLASS_MAP.get(domainClass);
    if(domain == null){
      Map<String, String> map = Maps.newLinkedHashMap();
      for (Field field : domainClass.getDeclaredFields()) {
        Column annotation = field.getAnnotation(Column.class);
        if(annotation != null && annotation.name().length() > 0){
          map.put(field.getName(), annotation.name());
        }
      }
      if(map.isEmpty()){
        for (Method method : domainClass.getDeclaredMethods()) {
          Column annotation = method.getAnnotation(Column.class);
          if(annotation != null && annotation.name().length() > 0){
            String name = method.getName();
            int i = name.startsWith("get") || name.startsWith("set")
                    ? 3 : (name.startsWith("is") ? 2 : 0);
            String key = name.substring(i, i + 1).toLowerCase() + name.substring(i + 1);
            map.put(key, annotation.name());
          }
        }
      }
      if(!map.isEmpty()){
        domain = ImmutableMap.copyOf(map);
        CLASS_MAP.put(domainClass, domain);
      }
    }
    return domain;
  }

  private static String addPoint(String src){
    if(src.endsWith(".")){
      return src;
    }
    else{
      return src + ".";
    }
  }
}
